/*
 * @Author: your name
 * @Date: 2021-06-01 00:10:49
 * @LastEditTime: 2021-06-01 00:13:53
 * @LastEditors: your name
 * @Description: In User Settings Edit
 * @FilePath: \workspace\projects\xmly\src\app\services\tools\scroll.service.ts
 */
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
export type ScrollEl = HTMLElement | Window;
export type EasyingFn = (t: number, b: number, c: number, d: number) => number;
function easeInOutCubic(t: number, b: number, c: number, d: number): number {
  const cc = c - b;
  let tt = t / (d / 2);
  if (tt < 1) {
    return (cc / 2) * tt * tt * tt + b;
  } else {
    return (cc / 2) * ((tt -= 2) * tt * tt + 2) + b;
  }
}
@Injectable({
  providedIn: 'root',
})
export class ScrollService {
  constructor(@Inject(DOCUMENT) private doc: Document) {}
  scrollTop(
    container: ScrollEl,
    targetTop = 0,
    easing?: EasyingFn,
    callback?: () => void
  ): void {
    const target = container || window;
    const scrollTop = this.getScroll(target);
    const startTime = Date.now();
    const frameFunc = () => {
      const duration = Date.now() - startTime;
      const topValue = (easing || easeInOutCubic)(
        duration,
        scrollTop,
        targetTop,
        450
      );
      this.setScrollTop(container, topValue);
      if (duration < 450) {
        requestAnimationFrame(frameFunc);
      } else {
        if (callback) {
          callback();
        }
      }
    };
    requestAnimationFrame(frameFunc);
  }
  setScrollTop(el: ScrollEl, topValue = 0): void {
    if (el === window) {
      this.doc.body.scrollTop = topValue;
      this.doc.documentElement.scrollTop = topValue;
    } else {
      (el as HTMLElement).scrollTop = topValue;
    }
  }
  getScroll(el: ScrollEl, top = true): number {
    const prop = top ? 'pageYOffset' : 'pageXOffset'; //window
    const method = top ? 'scrollTop' : 'scrollLeft'; //dom
    return el === window ? el[prop] : el[method];
  }
}
